package controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.sql.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import javax.swing.ImageIcon;

import model.Contact;

/**
 * This class operates with the contacts model, it handles the list of contacts
 * 
 * @author alexisstefanski
 * 
 */
public class ContactManager {

	/* Collection of contacts */
	private List<Contact> contacts = Collections
			.synchronizedList(new ArrayList<Contact>());
	private ReentrantLock l = new ReentrantLock();

	/**
	 * Add one contact to the list
	 * 
	 * @param new_contact
	 */
	public void addContact(Contact new_contact) {
		contacts.add(new_contact);
	}

	/**
	 * Add new infos to existing contact
	 * 
	 * @param new_contact
	 * @param id
	 */
	public void addContact(Contact new_contact, int id) {
		Contact c = contacts.get(id);
		c.setCompanyAddress(new_contact.getCompanyAddress());
		c.setDateCreated(new_contact.getDateCreated());
		c.setFirstname(new_contact.getFirstname());
		c.setHomeAddress(new_contact.getHomeAddress());
		c.setHomeNumber(new_contact.getHomeNumber());
		c.setHomepage(new_contact.getHomepage());
		c.setImgUrl(new_contact.getImgUrl());
		c.setLastname(new_contact.getLastname());
		c.setOfficeNumber(new_contact.getOfficeNumber());
		c.setPersonnalEmail(new_contact.getPersonnalEmail());
		c.setPersonnalMobile(new_contact.getPersonnalMobile());
		c.setSkypeUsername(new_contact.getSkypeUsername());
		c.setWorkMobile(new_contact.getWorkMobile());
		c.setGroup(new_contact.getGroup());
	}

	/**
	 * Remove a contact by its id
	 * 
	 * @param id
	 */
	public void removeContact(int id) {
		try {
			if (l.tryLock() || l.tryLock(2, TimeUnit.SECONDS)) {
				contacts.remove(id);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			l.unlock();
		}
	}

	/**
	 * Get a contact by its id
	 * 
	 * @param id
	 * @return the contact
	 */
	public Contact getContact(int id) {
		return contacts.get(id);
	}

	public List<Contact> getContacts() {
		return contacts;
	}

	public void deleteContact(Contact c) {
		try {
			if (l.tryLock() || l.tryLock(2, TimeUnit.SECONDS)) {
				contacts.remove(c);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			l.unlock();
		}

	}

	public void setContacts(List<Contact> contacts) {
		this.contacts = contacts;
	}

	/* For the cast at deserialization, causing warning */
	@SuppressWarnings("unchecked")
	/**
	 * Load the data from ser file
	 */
	public void loadData() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				// deserialize the file
				try (InputStream file = new FileInputStream("contacts.ser");
						InputStream buffer = new BufferedInputStream(file);
						ObjectInput input = new ObjectInputStream(buffer);) {
					if (l.tryLock() || l.tryLock(2, TimeUnit.SECONDS)) {

						contacts.clear();
						// deserialize the List
						contacts = (List<Contact>) input.readObject();
					}
				} catch (Exception e) {
					e.printStackTrace();
					System.out.println(e.getMessage());
				} finally {
					l.unlock();
				}

			}
		}).start();

	}

	/**
	 * Save the data in the file
	 */
	public void saveData() {
		/* try to write the file */
		new Thread(new Runnable() {

			@Override
			public void run() {
				try (OutputStream file = new FileOutputStream("contacts.ser");
						OutputStream buffer = new BufferedOutputStream(file);
						ObjectOutput output = new ObjectOutputStream(buffer);) {
					output.writeObject(contacts);
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println(e.getMessage());
				}

			}
		}).start();

	}

	/**
	 * Load the data from csv file
	 */
	public void loadDataFromCsv() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				String csvFile = "contacts.csv";
				BufferedReader br = null;
				String line = "";
				String cvsSplitBy = ",";

				try {
					if (l.tryLock() || l.tryLock(2, TimeUnit.SECONDS)) {
						br = new BufferedReader(new FileReader(csvFile));
						while ((line = br.readLine()) != null) {

							// use comma as separator
							// we use a replace in both writing and reading to
							// avoid
							// unexpected splitting if the user uses a comma
							String[] contact = line.split(cvsSplitBy);
							SimpleDateFormat sdf = new SimpleDateFormat();
							System.out.println(sdf.parse(contact[12].replace(
									"|COMA|", ",")));
							contacts.add(new Contact(contact[0].replace(
									"|COMA|", ","), contact[1].replace(
									"|COMA|", ","), contact[2].replace(
									"|COMA|", ","), contact[3].replace(
									"|COMA|", ","), contact[4].replace(
									"|COMA|", ","), contact[5].replace(
									"|COMA|", ","), contact[6].replace(
									"|COMA|", ","), contact[7].replace(
									"|COMA|", ","), contact[8].replace(
									"|COMA|", ","), contact[9].replace(
									"|COMA|", ","), contact[10].replace(
									"|COMA|", ","), contact[11].replace(
									"|COMA|", ","), contact[13].replace(
									"|COMA|", ","), sdf.parse(contact[12]
									.replace("|COMA|", ","))));
						}
						/*
						 * In the "csv version", images are stored in a .ser
						 * file for the app to be independant from any image
						 * file
						 */
						loadImages();
					}
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					if (br != null) {
						try {
							br.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					l.unlock();
				}
			}
		}).start();

	}

	/**
	 * Save all the contact images in a .ser file
	 */
	public void saveImages() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try (OutputStream file = new FileOutputStream("images.ser");
						OutputStream buffer = new BufferedOutputStream(file);
						ObjectOutput output = new ObjectOutputStream(buffer);) {
					for (Contact c : contacts) {
						output.writeObject(c.getImg());
					}

				} catch (IOException e) {
					e.printStackTrace();
					System.out.println(e.getMessage());
				}

			}
		}).start();
	}

	/**
	 * Load all the contact images from a .ser file
	 */
	public void loadImages() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				// deserialize the file
				try (InputStream file = new FileInputStream("images.ser");
						InputStream buffer = new BufferedInputStream(file);
						ObjectInput input = new ObjectInputStream(buffer);) {
					if (l.tryLock() || l.tryLock(2, TimeUnit.SECONDS)) {
						for (Contact c : contacts) {
							c.setImg((ImageIcon) input.readObject());
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					System.out.println(e.getMessage());
				} finally {
					l.unlock();
				}
			}
		}).start();

	}

	/**
	 * Save the data in the file
	 */
	public void saveDataToCsv() {
		/* try to write the file */
		new Thread(new Runnable() {

			@Override
			public void run() {
				/*
				 * In the "csv version", images are stored in a .ser file for
				 * the app to be independant from any image file
				 */
				saveImages();
				try (FileWriter writer = new FileWriter("contacts.csv");) {
					for (Contact c : contacts) {
						writer.append(c.toString());
						writer.append("\n");
						;
					}
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println(e.getMessage());
				}

			}
		}).start();

	}

}
